JavaScriptã®éåæã€ãã¬ãŒã¿ãã«ããŒãšZip颿°ã培åºè§£èª¬ãã¢ãã³ãªã¢ããªã±ãŒã·ã§ã³éçºã«äžå¯æ¬ ãªãéåæã¹ããªãŒã ãå¹ççã«çµåã»åŠçããæ¹æ³ãåŠã³ãŸãã
JavaScriptéåæã€ãã¬ãŒã¿ãã«ããŒïŒZipã«ããéåæã¹ããªãŒã çµåè¡
éåæããã°ã©ãã³ã°ã¯çŸä»£ã®JavaScriptéçºã®åºç€ã§ãããã¡ã€ã³ã¹ã¬ããããããã¯ããªãæäœãæ±ãããšãå¯èœã«ããŸããéåæã€ãã¬ãŒã¿ãšãžã§ãã¬ãŒã¿ã®å°å
¥ã«ãããéåæããŒã¿ã¹ããªãŒã ã®æ±ãã¯ãã管çãããããæŽç·Žããããã®ã«ãªããŸããããããŠä»ãéåæã€ãã¬ãŒã¿ãã«ããŒã®ç»å Žã«ããããããã®ã¹ããªãŒã ãæäœããããã®ããã«åŒ·åãªããŒã«ãæã«å
¥ããŸããç¹ã«äŸ¿å©ãªãã«ããŒã®äžã€ãzip颿°ã§ãããã«ããè€æ°ã®éåæã¹ããªãŒã ãã¿ãã«ã®åäžã¹ããªãŒã ã«çµåã§ããŸãããã®ããã°èšäºã§ã¯ãzipãã«ããŒãæ·±ãæãäžãããã®æ©èœããŠãŒã¹ã±ãŒã¹ãå®è·µçãªäŸãæ¢ããŸãã
éåæã€ãã¬ãŒã¿ãšãžã§ãã¬ãŒã¿ã®çè§£
zipãã«ããŒã«é£ã³èŸŒãåã«ãéåæã€ãã¬ãŒã¿ãšãžã§ãã¬ãŒã¿ãç°¡åã«åŸ©ç¿ããŸãããïŒ
- éåæã€ãã¬ãŒã¿ïŒ ã€ãã¬ãŒã¿ãããã³ã«ã«æºæ ãã€ã€ãéåæã«åäœãããªããžã§ã¯ãã§ããããã¯ã€ãã¬ãŒã¿çµæãªããžã§ã¯ãïŒ
{ value: any, done: boolean }ïŒã«è§£æ±ºããããããã¹ãè¿ãnext()ã¡ãœãããæã¡ãŸãã - éåæãžã§ãã¬ãŒã¿ïŒ éåæã€ãã¬ãŒã¿ãªããžã§ã¯ããè¿ã颿°ã§ãã
asyncããã³yieldããŒã¯ãŒãã䜿çšããŠéåæã«å€ãçæããŸãã
以äžã¯éåæãžã§ãã¬ãŒã¿ã®ç°¡åãªäŸã§ãïŒ
async function* generateNumbers(count) {
for (let i = 0; i < count; i++) {
await new Promise(resolve => setTimeout(resolve, 100)); // Simulate async operation
yield i;
}
}
ãã®ãžã§ãã¬ãŒã¿ã¯ãåyieldã®éã«100msã®é
å»¶ãæã¿ãªããã0ããcount - 1ãŸã§ã®æ°å€ãçæããŸãã
éåæã€ãã¬ãŒã¿ãã«ããŒã®ç޹ä»ïŒZip
zipãã«ããŒã¯ãAsyncIteratorãããã¿ã€ãã«è¿œå ãããéçã¡ãœããã§ãïŒãŸãã¯ç°å¢ã«ãã£ãŠã¯ã°ããŒãã«é¢æ°ãšããŠå©çšå¯èœã§ãïŒãããã¯è€æ°ã®éåæã€ãã¬ãŒã¿ïŒãŸãã¯éåæã€ãã©ãã«ïŒãåŒæ°ãšããŠåãåããæ°ããéåæã€ãã¬ãŒã¿ãè¿ããŸãããã®æ°ããã€ãã¬ãŒã¿ã¯ãé
åïŒã¿ãã«ïŒãçæããé
åå
ã®åèŠçŽ ã¯å¯Ÿå¿ããå
¥åã€ãã¬ãŒã¿ããååŸãããŸããã€ãã¬ãŒã·ã§ã³ã¯ãããããã®å
¥åã€ãã¬ãŒã¿ãå°œããæç¹ã§åæ¢ããŸãã
æ¬è³ªçã«ãzipã¯2ã€ã®ãžãããŒãéããããã«ãè€æ°ã®éåæã¹ããªãŒã ãããã¯ã¹ãããæ¹åŒã§çµåããŸããããã¯ãè€æ°ã®ãœãŒã¹ããã®ããŒã¿ãåæã«åŠçããå¿
èŠãããå Žåã«ç¹ã«äŸ¿å©ã§ãã
æ§æ
AsyncIterator.zip(iterator1, iterator2, ..., iteratorN);
æ»ãå€
å€ã®é åãçæããéåæã€ãã¬ãŒã¿ãåå€ã¯å¯Ÿå¿ããå ¥åã€ãã¬ãŒã¿ããååŸãããŸããããããã®å ¥åã€ãã¬ãŒã¿ãæ¢ã«éããããŠãããããšã©ãŒãã¹ããŒããå Žåãçµæã®ã€ãã¬ãŒã¿ãåæ§ã«éãããããšã©ãŒãã¹ããŒããŸãã
éåæã€ãã¬ãŒã¿ãã«ããŒZipã®ãŠãŒã¹ã±ãŒã¹
zipãã«ããŒã¯ãããŸããŸãªåŒ·åãªãŠãŒã¹ã±ãŒã¹ãå¯èœã«ããŸãã以äžã«ããã€ãã®äžè¬çãªã·ããªãªãæããŸãïŒ
- è€æ°ã®APIããã®ããŒã¿çµåïŒ 2ã€ã®ç°ãªãAPIããããŒã¿ãååŸããå
±éã®ããŒïŒäŸïŒãŠãŒã¶ãŒIDïŒã«åºã¥ããŠçµæãçµåããå¿
èŠããããšæ³åããŠã¿ãŠãã ãããåAPIã®ããŒã¿ã¹ããªãŒã ã«å¯ŸããŠéåæã€ãã¬ãŒã¿ãäœæãã
zipã䜿çšããŠããããäžç·ã«åŠçã§ããŸãã - ãªã¢ã«ã¿ã€ã ããŒã¿ã¹ããªãŒã ã®åŠçïŒ ãªã¢ã«ã¿ã€ã ããŒã¿ãæ±ãã¢ããªã±ãŒã·ã§ã³ïŒäŸïŒéèåžå Žãã»ã³ãµãŒããŒã¿ïŒã§ã¯ãè€æ°ã®æŽæ°ã¹ããªãŒã ãååšãããããããŸããã
zipã¯ãããã®æŽæ°ããªã¢ã«ã¿ã€ã ã§çžé¢ãããã®ã«åœ¹ç«ã¡ãŸããäŸãã°ãç°ãªãååŒæããã®è²·å€ãšå£²å€ãçµåããŠäžéäŸ¡æ Œãèšç®ãããªã©ã§ãã - 䞊åããŒã¿åŠçïŒ é¢é£ããŒã¿ã«å¯ŸããŠå®è¡ããå¿
èŠãããè€æ°ã®éåæã¿ã¹ã¯ãããå Žåã
zipã䜿çšããŠå®è¡ã調æŽããçµæãçµåã§ããŸãã - UIæŽæ°ã®åæïŒ ããã³ããšã³ãéçºã§ã¯ãUIãæŽæ°ããåã«å®äºããå¿
èŠãããè€æ°ã®éåææäœããããããããŸããã
zipã¯ãããã®æäœãåæããããã¹ãŠã®æäœãå®äºãããšãã«UIæŽæ°ãããªã¬ãŒããã®ã«åœ¹ç«ã¡ãŸãã
å®è·µçãªäŸ
zipãã«ããŒãããã€ãã®å®è·µçãªäŸã§èª¬æããŸãããã
äŸ1ïŒ2ã€ã®éåæãžã§ãã¬ãŒã¿ã®Zip
ãã®äŸã§ã¯ãæ°å€ãšæåã®ã·ãŒã±ã³ã¹ãçæãã2ã€ã®åçŽãªéåæãžã§ãã¬ãŒã¿ãzipããæ¹æ³ã瀺ããŸãïŒ
async function* generateNumbers(count) {
for (let i = 1; i <= count; i++) {
await new Promise(resolve => setTimeout(resolve, 50));
yield i;
}
}
async function* generateLetters(count) {
const letters = 'abcdefghijklmnopqrstuvwxyz';
for (let i = 0; i < count; i++) {
await new Promise(resolve => setTimeout(resolve, 75));
yield letters[i];
}
}
async function main() {
const numbers = generateNumbers(5);
const letters = generateLetters(5);
const zipped = AsyncIterator.zip(numbers, letters);
for await (const [number, letter] of zipped) {
console.log(`Number: ${number}, Letter: ${letter}`);
}
}
main();
// æåŸ
ãããåºåïŒéåæã®æ§è³ªäžãé åºãè¥å¹²ç°ãªãå ŽåããããŸãïŒïŒ
// Number: 1, Letter: a
// Number: 2, Letter: b
// Number: 3, Letter: c
// Number: 4, Letter: d
// Number: 5, Letter: e
äŸ2ïŒ2ã€ã®ã¢ãã¯APIããã®ããŒã¿ã®çµå
ãã®äŸã§ã¯ã2ã€ã®ç°ãªãAPIããããŒã¿ãååŸãããŠãŒã¶ãŒIDã«åºã¥ããŠçµæãçµåããã·ãã¥ã¬ãŒã·ã§ã³ãè¡ããŸãïŒ
async function* fetchUserData(userIds) {
for (const userId of userIds) {
await new Promise(resolve => setTimeout(resolve, 100));
yield { userId, name: `User ${userId}`, country: (userId % 2 === 0 ? 'USA' : 'Canada') };
}
}
async function* fetchUserPreferences(userIds) {
for (const userId of userIds) {
await new Promise(resolve => setTimeout(resolve, 150));
yield { userId, theme: (userId % 3 === 0 ? 'dark' : 'light'), notifications: true };
}
}
async function main() {
const userIds = [1, 2, 3, 4, 5];
const userData = fetchUserData(userIds);
const userPreferences = fetchUserPreferences(userIds);
const zipped = AsyncIterator.zip(userData, userPreferences);
for await (const [user, preferences] of zipped) {
if (user.userId === preferences.userId) {
console.log(`User ID: ${user.userId}, Name: ${user.name}, Country: ${user.country}, Theme: ${preferences.theme}, Notifications: ${preferences.notifications}`);
} else {
console.log(`Mismatched user data for ID: ${user.userId}`);
}
}
}
main();
// æåŸ
ãããåºå:
// User ID: 1, Name: User 1, Country: Canada, Theme: light, Notifications: true
// User ID: 2, Name: User 2, Country: USA, Theme: light, Notifications: true
// User ID: 3, Name: User 3, Country: Canada, Theme: dark, Notifications: true
// User ID: 4, Name: User 4, Country: USA, Theme: light, Notifications: true
// User ID: 5, Name: User 5, Country: Canada, Theme: light, Notifications: true
äŸ3ïŒReadableStreamã®åãæ±ã
ãã®äŸã§ã¯ãReadableStreamã€ã³ã¹ã¿ã³ã¹ã§zipãã«ããŒã䜿çšããæ¹æ³ã瀺ããŸããããã¯ããããã¯ãŒã¯ããã¡ã€ã«ããã®ã¹ããªãŒãã³ã°ããŒã¿ãæ±ãéã«ç¹ã«é¢é£æ§ããããŸãã
async function* readableStreamToAsyncGenerator(stream) {
const reader = stream.getReader();
try {
while (true) {
const { done, value } = await reader.read();
if (done) return;
yield value;
}
} finally {
reader.releaseLock();
}
}
async function main() {
const stream1 = new ReadableStream({
start(controller) {
controller.enqueue('Stream 1 - Part 1\n');
controller.enqueue('Stream 1 - Part 2\n');
controller.close();
}
});
const stream2 = new ReadableStream({
start(controller) {
controller.enqueue('Stream 2 - Line A\n');
controller.enqueue('Stream 2 - Line B\n');
controller.enqueue('Stream 2 - Line C\n');
controller.close();
}
});
const asyncGen1 = readableStreamToAsyncGenerator(stream1);
const asyncGen2 = readableStreamToAsyncGenerator(stream2);
const zipped = AsyncIterator.zip(asyncGen1, asyncGen2);
for await (const [chunk1, chunk2] of zipped) {
console.log(`Stream 1: ${chunk1}, Stream 2: ${chunk2}`);
}
}
main();
// æåŸ
ãããåºåïŒé åºãç°ãªãå ŽåããããŸãïŒïŒ
// Stream 1: Stream 1 - Part 1\n, Stream 2: Stream 2 - Line A\n
// Stream 1: Stream 1 - Part 2\n, Stream 2: Stream 2 - Line B\n
// Stream 1: undefined, Stream 2: Stream 2 - Line C\n
ReadableStreamã«é¢ããéèŠãªæ³šæç¹ïŒ äžæ¹ã®ã¹ããªãŒã ã仿¹ããå
ã«çµäºããå Žåãzipãã«ããŒã¯ãã¹ãŠã®ã¹ããªãŒã ãå°œãããŸã§ã€ãã¬ãŒã·ã§ã³ãç¶ããŸãããã®ãããæ¢ã«å®äºããã¹ããªãŒã ã«å¯ŸããŠã¯undefinedå€ã«ééããå¯èœæ§ããããŸããreadableStreamToAsyncGeneratorå
ã®ãšã©ãŒãã³ããªã³ã°ã¯ãæªåŠçã®æåŠãé²ããé©åãªã¹ããªãŒã ã®ã¯ããŒãºãä¿èšŒããããã«äžå¯æ¬ ã§ãã
ãšã©ãŒãã³ããªã³ã°
éåææäœãæ±ãéã«ã¯ãå
ç¢ãªãšã©ãŒãã³ããªã³ã°ãäžå¯æ¬ ã§ãã以äžã¯zipãã«ããŒã䜿çšããéã®ãšã©ãŒã®æ±ãæ¹ã§ãïŒ
- Try-Catchãããã¯ïŒ
for await...ofã«ãŒããtry-catchãããã¯ã§å²ã¿ãã€ãã¬ãŒã¿ã«ãã£ãŠã¹ããŒãããå¯èœæ§ã®ããäŸå€ããã£ããããŸãã - ãšã©ãŒäŒæïŒ å
¥åã€ãã¬ãŒã¿ã®ããããããšã©ãŒãã¹ããŒããå Žåã
zipãã«ããŒã¯ãã®ãšã©ãŒãçµæã®ã€ãã¬ãŒã¿ã«äŒæãããŸããã¢ããªã±ãŒã·ã§ã³ã®ã¯ã©ãã·ã¥ãé²ãããã«ããããã®ãšã©ãŒãé©åã«åŠçããŠãã ããã - ãã£ã³ã»ã«ïŒ éåæã€ãã¬ãŒã¿ã«ãã£ã³ã»ã«ãµããŒãã远å ããããšãæ€èšããŠãã ããã1ã€ã®ã€ãã¬ãŒã¿ã倱æãŸãã¯ãã£ã³ã»ã«ãããå ŽåãäžèŠãªäœæ¥ãé¿ããããã«ä»ã®ã€ãã¬ãŒã¿ããã£ã³ã»ã«ãããå ŽåããããŸããããã¯ãé·æéå®è¡ãããæäœãæ±ãéã«ç¹ã«éèŠã§ãã
async function main() {
async function* generateWithError(count) {
for (let i = 0; i < count; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
if (i === 2) {
throw new Error('Simulated error');
}
yield i;
}
}
const numbers1 = generateNumbers(5);
const numbers2 = generateWithError(5);
try {
const zipped = AsyncIterator.zip(numbers1, numbers2);
for await (const [num1, num2] of zipped) {
console.log(`Number 1: ${num1}, Number 2: ${num2}`);
}
} catch (error) {
console.error(`Error: ${error.message}`);
}
}
ãã©ãŠã¶ãšNode.jsã®äºææ§
éåæã€ãã¬ãŒã¿ãã«ããŒã¯JavaScriptã®æ¯èŒçæ°ããæ©èœã§ãããã©ãŠã¶ã§ã®éåæã€ãã¬ãŒã¿ãã«ããŒã®ãµããŒãã¯é²åããŠããŸããææ°ã®äºææ§æ å ±ã«ã€ããŠã¯ãMDNããã¥ã¡ã³ãã確èªããŠãã ãããå€ããã©ãŠã¶ããµããŒãããã«ã¯ãããªãã£ã«ããã©ã³ã¹ãã€ã©ïŒBabelãªã©ïŒã䜿çšããå¿ èŠããããããããŸããã
Node.jsã§ã¯ãéåæã€ãã¬ãŒã¿ãã«ããŒã¯æè¿ã®ããŒãžã§ã³ïŒéåžžã¯Node.js 18+ïŒã§å©çšå¯èœã§ãããããã®æ©èœãå©çšããã«ã¯ãäºææ§ã®ããããŒãžã§ã³ã®Node.jsã䜿çšããŠããããšã確èªããŠãã ããã䜿çšããã®ã«å¿ èŠãªã€ã³ããŒãã¯ãªããã°ããŒãã«ãªããžã§ã¯ãã§ãã
AsyncIterator.zipã®ä»£æ¿ææ®µ
AsyncIterator.zipãåºãå©çšå¯èœã«ãªãåã¯ãéçºè ã¯åæ§ã®æ©èœãå®çŸããããã«ã«ã¹ã¿ã å®è£ ãã©ã€ãã©ãªã«é ŒãããšããããããŸããã以äžã«ããã€ãã®ä»£æ¿ææ®µãæããŸãïŒ
- ã«ã¹ã¿ã å®è£
ïŒ éåæãžã§ãã¬ãŒã¿ãšPromiseã䜿çšããŠç¬èªã®
zip颿°ãäœæã§ããŸããããã«ããå®è£ ãå®å šã«å¶åŸ¡ã§ããŸãããããå€ãã®ã³ãŒããå¿ èŠã«ãªããŸãã it-utilsã®ãããªã©ã€ãã©ãªïŒit-utilsïŒjs-itãšã³ã·ã¹ãã ã®äžéšïŒã®ãããªã©ã€ãã©ãªã¯ãéåæã€ãã¬ãŒã¿ãå«ãã€ãã¬ãŒã¿ãæ±ãããã®ãŠãŒãã£ãªãã£é¢æ°ãæäŸããŸãããããã®ã©ã€ãã©ãªã¯ãåãªãzip以äžã®å¹ åºãæ©èœãæäŸããããšããããããŸãã
éåæã€ãã¬ãŒã¿ãã«ããŒã䜿çšããããã®ãã¹ããã©ã¯ãã£ã¹
zipã®ãããªéåæã€ãã¬ãŒã¿ãã«ããŒã广çã«äœ¿çšããããã«ã以äžã®ãã¹ããã©ã¯ãã£ã¹ãèæ
®ããŠãã ããïŒ
- éåææäœãçè§£ããïŒ PromiseãAsync/Awaitãéåæã€ãã¬ãŒã¿ãå«ãéåæããã°ã©ãã³ã°ã®æŠå¿µããã£ãããšçè§£ããŠããããšã確èªããŠãã ããã
- ãšã©ãŒãé©åã«åŠçããïŒ äºæããªãã¢ããªã±ãŒã·ã§ã³ã®ã¯ã©ãã·ã¥ãé²ãããã«ãå ç¢ãªãšã©ãŒãã³ããªã³ã°ãå®è£ ããŠãã ããã
- ããã©ãŒãã³ã¹ãæé©åããïŒ éåææäœã®ããã©ãŒãã³ã¹ãžã®åœ±é¿ã«æ³šæããŠãã ããã䞊ååŠçããã£ãã·ã³ã°ãªã©ã®æè¡ã䜿çšããŠå¹çãåäžãããŸãã
- ãã£ã³ã»ã«ãæ€èšããïŒ ãŠãŒã¶ãŒãã¿ã¹ã¯ãäžæã§ããããã«ãé·æéå®è¡ãããæäœã«ã¯ãã£ã³ã»ã«ãµããŒããå®è£ ããŸãã
- 培åºçã«ãã¹ãããïŒ éåæã³ãŒããããŸããŸãªã·ããªãªã§æåŸ ã©ããã«åäœããããšã確èªããããã«ãå æ¬çãªãã¹ããäœæããŠãã ããã
- 説æçãªå€æ°åã䜿çšããïŒ æç¢ºãªååã¯ãã³ãŒãã®çè§£ãšä¿å®ã容æã«ããŸãã
- ã³ãŒãã«ã³ã¡ã³ããä»ããïŒ ã³ãŒãã®ç®çãèªæã§ãªãããžãã¯ã説æããããã«ã³ã¡ã³ãã远å ããŸãã
é«åºŠãªãã¯ããã¯
éåæã€ãã¬ãŒã¿ãã«ããŒã®åºæ¬ã«æ £ããããããé«åºŠãªãã¯ããã¯ãæ¢æ±ã§ããŸãïŒ
- ãã«ããŒã®é£éïŒ è€æ°ã®éåæã€ãã¬ãŒã¿ãã«ããŒãé£éãããŠãè€éãªããŒã¿å€æãå®è¡ã§ããŸãã
- ã«ã¹ã¿ã ãã«ããŒïŒ åå©çšå¯èœãªããžãã¯ãã«ãã»ã«åããããã«ãç¬èªã®ã«ã¹ã¿ã éåæã€ãã¬ãŒã¿ãã«ããŒãäœæã§ããŸãã
- ããã¯ãã¬ãã·ã£ãŒã®åŠçïŒ ã¹ããªãŒãã³ã°ã¢ããªã±ãŒã·ã§ã³ã§ã¯ãã³ã³ã·ã¥ãŒããããŒã¿ã§å§åãããã®ãé²ãããã«ããã¯ãã¬ãã·ã£ãŒã¡ã«ããºã ãå®è£ ããŸãã
çµè«
JavaScriptã®éåæã€ãã¬ãŒã¿ãã«ããŒã«ãããzipãã«ããŒã¯ãè€æ°ã®éåæã¹ããªãŒã ãçµåããããã®åŒ·åã§æŽç·Žãããæ¹æ³ãæäŸããŸãããã®æ©èœãšãŠãŒã¹ã±ãŒã¹ãçè§£ããããšã§ãéåæã³ãŒãã倧å¹
ã«ç°¡çŽ åããããå¹ççã§å¿çæ§ã®é«ãã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ã§ããŸããã³ãŒãã®å
ç¢æ§ã確ä¿ããããã«ããšã©ãŒåŠçãããã©ãŒãã³ã¹ã®æé©åããã£ã³ã»ã«ã®æ€èšãå¿ããªãã§ãã ãããéåæã€ãã¬ãŒã¿ãã«ããŒãããåºãæ¡çšãããã«ã€ããŠãçŸä»£ã®JavaScriptéçºã«ãããŠãŸããŸãéèŠãªåœ¹å²ãæããããšã¯ééããããŸããã
ããŒã¿éçŽåã®Webã¢ããªã±ãŒã·ã§ã³ããªã¢ã«ã¿ã€ã ã·ã¹ãã ããŸãã¯Node.jsãµãŒããŒãæ§ç¯ããŠããå Žåã§ããzipãã«ããŒã¯éåæããŒã¿ã¹ããªãŒã ããã广çã«ç®¡çããã®ã«åœ¹ç«ã¡ãŸãããã®ããã°èšäºã§æäŸãããŠããäŸã詊ããŠã¿ãŠãzipãä»ã®éåæã€ãã¬ãŒã¿ãã«ããŒãšçµã¿åãããŠãJavaScriptã«ãããéåæããã°ã©ãã³ã°ã®å¯èœæ§ãæå€§éã«åŒãåºããŠã¿ãŠãã ããããã©ãŠã¶ãšNode.jsã®äºææ§ã«æ³šæãæããããåºããªãŒãã£ãšã³ã¹ã«å±ããããã«å¿
èŠã«å¿ããŠããªãã£ã«ããã©ã³ã¹ãã€ã«ãè¡ã£ãŠãã ããã
ããããŒã³ãŒãã£ã³ã°ïŒãããŠãããªãã®éåæã¹ããªãŒã ãåžžã«åæãããããšãé¡ã£ãŠããŸãïŒ